package com.huawei.jnjd.level1.simpleCheck;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.IdentityHashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import com.huawei.jnjd.level1.simpleCheck.entity.SortTool;

/***
 * 
* <p>Title: SimpleCheckSystem</p>
* <p>Description: 源文件核心代码(单个功能模块化很重要(单个方法仅完成单个功能，便于模块复用)！！！！！！！！！！)</p>
* <p>Company: lty</p>
* @author liuhao
* @date 2017年7月6日 下午3:49:25
 */
public class SimpleCheckSystem
{
	//新增类的属性
	private String cdrString;
	private String cdrFormat;
	private boolean sortFlag;
	
	private String checkCondition;

    /**
     * 
     * 系统初始化。执行init()后，系统按照输入的话单内容和话单顺序格式要求重置话单数据并按照要求输出。
     * 该方法每次执行时，原有的数据一律要全部清空。
     * 
     * @param cdrString 话单内容，格式参照系统规则说明
     * @param cdrFormat 话单顺序格式要求，格式参照系统规则说明
     * @param sortFlag  是否以排序方式输出话单内容
     * 
     * @return 按照话单顺序格式要求解析输入，并按照系统规则中明确的输出格式要求输出。
     * 
     * 如果输出有多行话单，需要根据sortFlag进行处理。 
     * 如果取值为false，则直接按照每行话单在输入中的先后顺序输出；
     * 如果取值为true，则需要首先按照Time字段的时间先后进行排序，时间在前的在前面输出；
     * 如果Time字段一致，则再按照Channel字段的字典序来排序。
     * 
     * 无需考虑Time和Channel都相同的情况
     */
    public String init(String cdrString, String cdrFormat, boolean sortFlag)
    {
    	//与类属性关联
    	this.cdrString = cdrString;
    	this.cdrFormat = cdrFormat;
    	this.sortFlag = sortFlag;
    	
    	//对输入字符串和格式处理成一个List<Map>
        List<Map<String, String>> list = assembleMapListHandler();
        
        //对list结果集按照默认规则进行排序
        listSortHandler(list);
        
        //对list结果根据默认元素先后排序并转成字符串输出
        return listToString(list);
    }
    
    /***
     * 
    * <p>Title: listSortHandler</p>
    * <p>Description: 对指定的list按照给定规则进行排序</p>
    * @param list
     */
    private void listSortHandler(List<Map<String, String>> list){
    	String[] array = cdrString.split("\r\n");
    	
    	if(array.length > 1 && sortFlag){
        	Collections.sort(list, new Comparator<Map<String, String>>() {
				@Override
				public int compare(Map<String, String> o1, Map<String, String> o2) {
					DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
					Date date1 = null;
					Date date2 = null;
					try {
						date1 = (Date) df.parse(o1.get("Time"));
						date2 = (Date) df.parse(o2.get("Time"));
					} catch (ParseException e) {
						
					}
					if(date1.before(date2)){
						return -1;
					}
					else if(date1.after(date2)){
						return 1;
					}
					else{
						return o1.get("Channel").compareTo(o2.get("Channel"));
					}
				}
			});
        }
    }
    
    /***
     * 
    * <p>Title: assembleMapListHandler</p>
    * <p>Description: 将字符串分割解析</p>
    * @return List<Map> 集合
     */
    private List<Map<String, String>> assembleMapListHandler(){
    	List<Map<String, String>> list = new ArrayList<>();
    	
        String[] array = cdrString.split("\r\n");
        
        for(String str : array){
        	//调用单条字符串解析处理方法
        	Map<String, String> map = parseStringByFormatHandler(str, cdrFormat);
        	list.add(map);
        }
        
        return list;
    }

    /***
     * 
    * <p>Title: listToString</p>
    * <p>Description: 将list按照元素默认排序规则转成字符串</p>
    * @param list
    * @return
     */
	private String listToString(List<Map<String, String>> list) {
		StringBuilder sbOuter = new StringBuilder();
        
        for(Map<String, String> map : list){
        	StringBuilder sbInner = new StringBuilder();
        	sbInner.append(map.get("Time") == null ? "" : map.get("Time")).append("|").append(map.get("Msisdn") == null ? "" : map.get("Msisdn")).append("|").append(map.get("Channel") == null ? "" : map.get("Channel")).append("|").append(map.get("IP") == null ? "" : map.get("IP")).append("|").append(map.get("UserAgent") == null ? "" : map.get("UserAgent")).append("|").append(map.get("Result") == null ? "" : map.get("Result")).append("|").append(map.get("Fee") == null ? "" : map.get("Fee"));
        	sbOuter.append(sbInner).append("\r\n");
        }
		return sbOuter.toString();
	}
    
	/***
	 * 
	* <p>Title: parseStringByFormatHandler</p>
	* <p>Description: 根据给定的格式解析字符串</p>
	* @param entityStr 传递的需要解析的字符串
	* @param format  解析格式
	* @return  map集合
	 */
    private Map<String, String> parseStringByFormatHandler(String entityStr, String format){
    	Map<String, String> map = new HashMap<>();
    	
    	String[] vals = entityStr.split("\\|");//字符串值数组
    	String[] keys = format.split("\\|");//格式数组
    	
    	for(int i = 0; i< keys.length; i++){
    		map.put(keys[i], vals[i]);//封装成一个Map
    	}
    	
    	return map;
    }
    
    /**
     * 
     * 基于init方法的输入数据和输入输出规则要求，进一步对话单进行有效性检查，并按照规则输出满足要求的记录。
     * 
     * @param checkCondition 话单校验条件，具体参见校验表达式规则
     * 
     * @return 基于init方法指定的要求，对话单校验处理，并将符合要求的话单按要求输出。
     * 如果输出有多行话单，同样按照init中的排序规则输出。
     * 
     */
    public String checkCdr(String checkCondition) 
    {
    	//与类属性关联
    	this.checkCondition = checkCondition;
    	
    	//解析条件
        Map<String, String> conditionMap = parseConditionsHandler();
        
        //组装List<Map>
        List<Map<String, String>> list = assembleMapListHandler();
        
        //过滤处理
        filterHandler(conditionMap, list);
        
        //元素排序
        listSortHandler(list);
        
        //字符串输出
        return listToString(list);
    }

    /***
     * 
    * <p>Title: filterHandler</p>
    * <p>Description: 过滤处理（这里要注意集合类型遍历时候删除功能操作只能用Iterator）</p>
    * @param conditionMap
    * @param list
     */
	private void filterHandler(Map<String, String> conditionMap, List<Map<String, String>> list) {
		for(Iterator<Map<String, String>> iterator = list.iterator(); iterator.hasNext();){
        	Map<String, String> map = iterator.next();
        	//重要！！！！！！这里必须指定该状态，以防多个条件相同处理删除报IllegalStateException！！！！！！！！！
        	boolean delState = false;
        	for(Iterator<String> iterator2 = map.keySet().iterator(); iterator2.hasNext();){
        		String key = iterator2.next();
        		for(Iterator<String> iterator3 = conditionMap.keySet().iterator(); iterator3.hasNext();){
            		String key2 = iterator3.next();
            		if(key2.equals(key)){
            			String value = conditionMap.get(key2);
            			
            			if(value.indexOf("=") != -1){
            				int target = Integer.valueOf(value.substring(1));
            				if(Integer.valueOf(map.get(key)) != target){
            					if(!delState){
            						iterator.remove();
            						delState = true;
            					}
            				}
            			}
            			if(value.indexOf(">") != -1){
            				int target = Integer.valueOf(value.substring(1));
            				if(Integer.valueOf(map.get(key)) <= target){
            					if(!delState){
            						iterator.remove();
            						delState = true;
            					}
            				}
            			}
            			if(value.indexOf("<") != -1){
            				int target = Integer.valueOf(value.substring(1));
            				if(Integer.valueOf(map.get(key)) >= target){
            					if(!delState){
            						iterator.remove();
            						delState = true;
            					}
            				}
            			}
            			if(value.indexOf("startWith") != -1){
            				String target = value.substring("startWith(\"".length(),value.length()-2);
            				if(!map.get(key).startsWith(target)){
            					if(!delState){
            						iterator.remove();
            						delState = true;
            					}
            				}
            			}
            			if(value.indexOf("contains") != -1){
            				String target = value.substring("contains(\"".length(),value.length()-2);
            				if(!map.get(key).contains(target)){
            					if(!delState){
            						iterator.remove();
            						delState = true;
            					}
            				}
            			}
            			if(value.substring(0,1).equals("\"")){
            				String target = value.substring(1,value.length()-1);
            				if(!map.get(key).equals(target)){
            					if(!delState){
            						iterator.remove();
            						delState = true;
            					}
            				}
            			}
            		}
            	}
        	}
        }
	}
    
	/***
	 * 
	* <p>Title: parseConditionsHandler</p>
	* <p>Description: 解析条件</p>
	* @return Map
	 */
    private Map<String, String> parseConditionsHandler() {
    	String[] conditions = checkCondition.split("&&");
    	
    	//重要！！！！！！IdentityHashMap可以存放key相同的值，而HashMap不能！！！！！！！！！！
    	Map<String, String> conditionMap = new IdentityHashMap<>();
    	for(String condition : conditions){
    		String[] arr = condition.split(":");
    		conditionMap.put(arr[0], arr[1]);
    	}
    	
		return conditionMap;
	}

	/**
     * 
     * 以Msisdn字段为统计维度，对所有通过校验的话单进行处理，输出话单累加后的Fee值最大的Msisdn字段。
     * 如果有多个Msisdn的Fee值相同，则按照Msisdn字段的字典序排序，输出第一个Msisdn。
     * 
     * @return Fee值累加总和最大的第一个Msisdn字段。
     */
    public String queryMsisdnTop()
    {
    	Map<String, String> conditionMap = parseConditionsHandler();
        
        List<Map<String, String>> list = assembleMapListHandler();
        
        filterHandler(conditionMap, list);
        
        //按照统计规则进行统计处理
        List<SortTool> sortTools = statSortHandler(list, "Msisdn");
        
        return sortTools.get(0).getName();
    }
    
    
    /**
     * 
     * 以每日[00:00:00,23:59:59]为核算单位（日期为闭区间，包含起止和结束时间），统计各个渠道的推广数据，
     * 所有通过校验的话单的Fee累加值最大的为最优日推广渠道。
     * 
     * 如果Fee的累加值出现相同的多个渠道，则按照Channel字段的字典序排序，选取第一个渠道。
     * 
     * @return 满足条件的第一个Channel
     */
    public String queryDayTop() 
    {
    	Map<String, String> conditionMap = parseConditionsHandler();
        
        List<Map<String, String>> list = assembleMapListHandler();
        
        filterHandler(conditionMap, list);
        
        //按照统计规则进行统计处理
        List<SortTool> sortTools = statSortHandler(list, "Channel");
        
        return sortTools.get(0).getName().split("_")[0];
    }

    /***
     * 
    * <p>Title: statSortHandle</p>
    * <p>Description: 根据对应规则进行统计操作</p>
    * @param list
    * @param type
    * @return
     */
	private List<SortTool> statSortHandler(List<Map<String, String>> list, String type) {
		List<SortTool> sortTools = new ArrayList<>();
        for(Map<String, String> map : list){
        	String key = "";
        	if(type.equals("Channel")){
        		key = map.get("Channel").concat("_").concat(map.get("Time").substring(0,10));
        	}
        	else if(type.equals("Msisdn")){
        		key = map.get("Msisdn");
        	}
        	
        	boolean isExisted = false;
        	for(SortTool sortTool : sortTools){
        		if(sortTool.getName().equals(key)){
        			sortTool.setVal(sortTool.getVal() + Integer.valueOf(map.get("Fee")));
        			isExisted = true;
        			break;
        		}
        	}
        	
        	if(!isExisted){
        		SortTool sortTool = new SortTool(key, Integer.valueOf(map.get("Fee")));
        		sortTools.add(sortTool);
        	}
        }
        
        Collections.sort(sortTools,new Comparator<SortTool>() {

			@Override
			public int compare(SortTool o1, SortTool o2) {
				if(o1.getVal() < o2.getVal()){
					return 1;
				}
				else if(o1.getVal() > o2.getVal()){
					return -1;
				}
				else{
					return o1.getName().compareTo(o2.getName());
				}
				
			}
        	
		});
		return sortTools;
	}
    
}
